package io.lckgroup.modules.lck.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import io.lckgroup.common.utils.Constant;
import io.lckgroup.modules.lck.entity.CustomerInfoEntity;
import io.lckgroup.modules.lck.entity.wxgzhvo.*;
import org.apache.commons.collections.map.HashedMap;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.ServletInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class WxUtils {

    private static final String TOKEN = "abc";
    private static final String APPID = Constant.WxgzhConfig.GZH_APPID;
    private static final String APPSECRET = Constant.WxgzhConfig.GZH_APPSECRET;
    //获取网页授权token的URL
    private static final String GET_WEB_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    //获取用户信息URL
    private static final String GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
    //获取基本token的URL
    private static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    //获取调用微信JS接口票据的url
    private static final String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    private static String accessToken;
    private static Long expiresTime;
    private static String ticket;
    private static Long ticket_expiresTime;

    /**
     * 微信公众号验证签名
     *
     * @param timestamp
     * @param signature
     * @param nonce
     * @return
     * @author tw
     */
    public static boolean check(String timestamp, String signature, String nonce) {

        // 1）将token、timestamp、nonce三个参数进行字典序排序
        String[] strs = new String[]{TOKEN, timestamp, nonce};
        Arrays.sort(strs);
        //2）将三个参数字符串拼接成一个字符串进行sha1加密
        String str = strs[0] + strs[1] + strs[2];
        String mysig = sha1(str);
        //3）开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
        return mysig.equals(signature);
    }

    /**
     * 进行sha1加密
     *
     * @param str
     * @return
     * @author tw
     */
    public static String sha1(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes("UTF-8"));

            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 处理微信服务器返回的xml数据包
     *
     * @param inputStream
     * @return 返回map
     * @throws DocumentException
     * @author tw
     */
    public static Map<String, String> parseRequest(ServletInputStream inputStream) throws DocumentException {
        Map<String, String> map = new HashedMap();
        SAXReader reader = new SAXReader();
        //读取输入流获取文档对象
        Document document = reader.read(inputStream);
        //根据文档对象获取根节点
        Element root = document.getRootElement();
        //获取根节点的所有子节点
        List<Element> elements = root.elements();
        for (Element e : elements) {
            map.put(e.getName(), e.getStringValue());
        }
        return map;
    }

    /**
     * 用于处理事件和消息的回复
     *
     * @param resultMap
     * @return 返回的是xml数据包
     * @author tw
     */
    public static String getResponse(Map<String, String> resultMap) {
        BaseMessage msg = null;
        String msgType = resultMap.get("MsgType");
        switch (msgType) {
            case "text":
                //处理文本消息
                msg = dealTextMessage(resultMap);
                break;
            case "image":
                break;
            case "voice":
                break;
            case "video":
                break;
            case "music":
                break;
            case "location":
                break;
            default:
                break;
        }
        //把消息对象转换为xml数据包
        if (msg != null) {
            return beanToXml(msg);
        }
        return null;
    }

    /**
     * 把消息对象处理为xml数据包
     *
     * @param msg
     * @return
     * @author tw
     */
    private static String beanToXml(BaseMessage msg) {
        XStream stream = new XStream();
        //设置需要处理@XStreamAlias("xml")注释的类
        stream.processAnnotations(TextMessage.class);
        stream.processAnnotations(ImageMessage.class);
        stream.processAnnotations(MusicMessage.class);
        stream.processAnnotations(VideoMessage.class);
        stream.processAnnotations(VoiceMessage.class);
        String xml = stream.toXML(msg);
        return xml;
    }

    /**
     * 处理文本消息
     *
     * @param resultMap
     * @return
     * @author tw
     */
    private static BaseMessage dealTextMessage(Map<String, String> resultMap) {
        TextMessage tm = new TextMessage(resultMap, "http://twwx.nat300.top/h5");
        return tm;
    }

    /**
     * 发送http get请求
     *
     * @param url
     * @return 返回json对象
     * @author tw
     */
    public static JSONObject httpGet(String url) {

        HttpClient client = HttpClientBuilder.create().build();//构建一个Client
        HttpGet get = new HttpGet(url);    //构建一个GET请求
        HttpResponse response = null;//提交GET请求
        try {
            response = client.execute(get);
        } catch (IOException e) {
            e.printStackTrace();
        }
        HttpEntity result = response.getEntity();//拿到返回的HttpResponse的"实体"
        String content = null;
        try {
            content = EntityUtils.toString(result, "UTF-8");
        } catch (IOException e) {
//            e.printStackTrace();
        }
        //把信息封装为json
        JSONObject jsonObject = JSONObject.parseObject(content);
        return jsonObject;
    }

    /**
     * 获取网页授权token
     *
     * @param code
     * @return
     */
    public static JSONObject getWebAccessToken(String code) {
        String result = HttpClientUtil.doGet(GET_WEB_ACCESS_TOKEN_URL.replace("APPID", APPID).replace("SECRET", APPSECRET).replace("CODE", code));
        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject;
    }

    /**
     * 根据openID和access_token获取用户信息
     *
     * @param access_token
     * @param openId
     * @return
     */
    public static JSONObject getUserinfo(String access_token, String openId) {
        String result = HttpClientUtil.doGet(GET_USERINFO_URL.replace("ACCESS_TOKEN", access_token).replace("OPENID", openId));
        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject;
    }

    /**
     * 获取基本的accesstoken
     *
     * @return
     */
    public static String getAccessToken() {
        //accesstoken为空或者失效才去获取
        if (accessToken == null || new Date().getTime() > expiresTime) {
            String result = HttpClientUtil.doGet(GET_ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET));
            JSONObject jsonObject = JSON.parseObject(result);
            accessToken = jsonObject.getString("access_token");
            Long expires_in = jsonObject.getLong("expires_in");
            //设置凭据失效时间
            expiresTime = new Date().getTime() + ((expires_in - 60) * 1000);
        }
        return accessToken;
    }

    /**
     * 获取JSSDK的ticket
     *
     * @return
     */
    public static String getTicket() {
        //ticket为空或者失效才去获取
        if (ticket == null || new Date().getTime() > ticket_expiresTime) {
            String result = HttpClientUtil.doGet(GET_TICKET_URL.replace("ACCESS_TOKEN", getAccessToken()));
            JSONObject jsonObject = JSON.parseObject(result);
            ticket = jsonObject.getString("ticket");
            Long expires_in = jsonObject.getLong("expires_in");
            //设置凭据失效时间
            ticket_expiresTime = new Date().getTime() + ((expires_in - 60) * 1000);
        }
        return ticket;
    }

    /**
     * 功能描述: <br>
     * 〈〉使用code获取用户信息,并封装为 CustomerInfoEntity
     *
     * @Param: [code]
     * @Return: io.lckgroup.modules.lck.entity.CustomerInfoEntity
     * @Author: 唐伟
     * @Date: 2020/3/20 14:40
     */
    public static CustomerInfoEntity userInfo(String code) {
        //3通过code换区网页授权access_token
        JSONObject jsonObject = getWebAccessToken(code);
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        //带着openid和access_token 获取用户信息
        JSONObject jsonObject1 = getUserinfo(access_token, openid);
        //将用户信息存入CustomerInfoEntity
        CustomerInfoEntity customer = new CustomerInfoEntity();
        customer.setNickname(jsonObject1.getString("nickname"));
        customer.setHeadImg(jsonObject1.getString("headimgurl"));
        customer.setOpenId(openid);
        customer.setSex(jsonObject1.getInteger("sex"));
        return customer;
    }
}
